Naukri Job Filter Automation: My Development Journey

Last Updated on April 21, 2025
✅ Completed
#Automation #JavaScript #WebScraping #JobSearch #UserScript

As a job seeker navigating through numerous job listings on Naukri.com, I found myself spending hours filtering through jobs that didn't match my skills or requirements. To streamline this process, I developed a browser automation script that would filter jobs based on custom criteria and export results for later review. This blog documents my development journey, the challenges faced, and solutions implemented along the way.

More you know!

Naukri already has a search filter but the search field sometimes works as OR rather than AND which i want. so this script filter the job which require both skills. This script uses already build in search option, search for the skills on naukri then use this script.

Project Inception: Defining the Problem

My job search on Naukri.com was becoming increasingly time-consuming. With hundreds of listings to sift through, I needed a way to:

Challenge #1: Understanding Naukri.com's DOM Structure

Before writing any code, I needed to understand how job listings were structured in the website's HTML. The dynamic nature of modern websites made this challenging, as elements could load asynchronously or change based on user interactions.

Solution:

I used Chrome DevTools to inspect the DOM structure thoroughly. By examining job cards, pagination elements, and filter components, I identified stable CSS selectors that could reliably target the necessary elements. I documented these selectors meticulously to ensure the script's robustness.

Naukri DOM Inspection

Building the Core Functionality

With the DOM structure mapped out, I moved on to implementing the core filtering logic.

Challenge #2: Extracting Job Details

Each job card contained various pieces of information like title, company name, experience required, rating, and skills. Extracting these consistently across all job listings required handling different formats and missing information.

Solution:

I developed a function to parse job cards and extract relevant details. The function used querySelector and querySelectorAll methods with the previously identified selectors, and included fallback logic for missing information.


extractJobDetails(jobCard) {
    try {
        // Job ID
        const jobId = jobCard.getAttribute('data-job-id') || 'N/A';
        
        // Job Title
        const titleElement = jobCard.querySelector('.title');
        const jobTitle = titleElement ? titleElement.textContent.trim() : 'N/A';
        const jobLink = titleElement ? titleElement.getAttribute('href') : 'N/A';
        
        // Company Name
        const companyElement = jobCard.querySelector('.comp-name');
        const companyName = companyElement ? companyElement.textContent.trim() : 'N/A';
        
        // Rating
        const ratingElement = jobCard.querySelector('.rating .main-2');
        const rating = ratingElement ? ratingElement.textContent.trim() : 'N/A';
        
        // Experience
        const expElement = jobCard.querySelector('.exp-wrap .expwdth');
        const experience = expElement ? expElement.textContent.trim() : 'N/A';
        
        // Salary
        const salaryElement = jobCard.querySelector('.sal-wrap span[title]');
        const salary = salaryElement ? salaryElement.getAttribute('title') : 'N/A';
        
        // Location
        const locationElement = jobCard.querySelector('.loc-wrap .locWdth');
        const location = locationElement ? locationElement.textContent.trim() : 'N/A';
        
        // Skills/Technologies
        const skillsElements = jobCard.querySelectorAll('.tags-gt .tag-li');
        const skills = Array.from(skillsElements).map(el => el.textContent.trim());
        
        // Posted Date
        const dateElement = jobCard.querySelector('.job-post-day');
        const postedDateText = dateElement ? dateElement.textContent.trim() : 'N/A';
        const postedDate = this.parsePostedDate(postedDateText);
        
        // Job Description (partial)
        const descElement = jobCard.querySelector('.job-desc');
        const description = descElement ? descElement.textContent.trim() : 'N/A';
        
        return {
        jobId,
        jobTitle,
        jobLink,
        companyName,
        rating,
        experience,
        salary,
        location,
        skills,
        postedDateText,
        postedDate,
        description
        };
    } catch (error) {
        console.error("Error extracting job details:", error);
        return null;
    }
}
                    

Challenge #3: Implementing Skill-Based Filtering

The main purpose of the script was to filter jobs based on required skills. However, skills were often presented inconsistently - sometimes as tags, sometimes within job descriptions, and with varying capitalizations or abbreviations.

Solution:

I implemented a flexible matching algorithm that:

  • Normalized text by converting to lowercase
  • Searched for skills in multiple areas of the job listing
  • Allowed for partial matches (e.g., "React" would match "ReactJS")
  • Used a scoring system based on the number of matching skills

const combinedText = (description.toLowerCase() + ' ' + skills.join(' ').toLowerCase());


const hasAllRequiredSkills = (job, requiredSkills) => {
    if (!requiredSkills || requiredSkills.length === 0) {
        return true;
    }
    
    const combinedText = job.combinedText;
    
    // Check if all required skills are present in the combined text
    return requiredSkills.every(requiredSkill => {
        const requiredSkillLower = requiredSkill.toLowerCase().trim();
        return combinedText.includes(requiredSkillLower);
    });
    };

    config.requiredSkills = document.getElementById('skills-input').value
    .split(',')
    .map(s => s.trim())
    .filter(s => s.length > 0);
                                    

Enhancing User Experience

With the core filtering logic in place, I focused on creating a user-friendly interface to control the script's behavior.

Challenge #4: Creating a Control Panel

The script needed input controls for users to specify their filtering criteria, but I didn't want to interfere with Naukri's existing UI or require external dependencies.

Solution:

I designed a floating control panel using pure JavaScript and CSS that would overlay on top of Naukri's interface. The panel included:

  • A text input for required skills (comma-separated)
  • A number input for minimum job rating
  • A checkbox for including/excluding unrated jobs
  • A number input for maximum pages to search
  • Action buttons for filtering, multi-page search, and exporting results
naukri-Floating control panel

Automating Multi-Page Searches

To make the script truly useful, it needed to handle pagination and collect results across multiple pages.

Challenge #5: Handling Pagination

Automating navigation between pages without breaking the user experience or triggering anti-bot measures was tricky. Additionally, I needed to track the current page number and determine when the last page was reached.

Solution:

I implemented a pagination system that:

  • Used the native "Next" button to navigate between pages
  • Added delays between page transitions to mimic human behavior
  • Parsed the pagination controls to determine the current page and total pages
  • Stored collected job data across page transitions

const goToNextPage = () => {
    const nextButton = document.querySelector('.styles_btn-secondary__2AsIP:not(.styles_previous__PobAs)');
    if (nextButton && !nextButton.hasAttribute('disabled')) {
        console.log('Navigating to next page...');
        nextButton.click();
        return true;
    } else {
        console.log('Next button not available or disabled');
        return false;
    }
    };
                

Key Commit:

fixed max page find
f1dcda4

This commit resolved an issue with correctly identifying the maximum available pages in search results, ensuring the script would not attempt to navigate beyond available pages. Hint! there was no need to know max pages just chek if next page is same as last one.

Adding Progress Tracking

For longer searches across multiple pages, users needed visibility into the script's progress.

Challenge #6: Tracking and Displaying Progress

Without feedback, users might think the script had stalled or failed when processing multiple pages. Additionally, accurate page tracking was complicated by asynchronous page loading.

Solution:

I added a visual progress bar to the control panel that updated in real-time as the script navigated through pages. The script also displayed the current page number and a running count of matching jobs found.

Key Commit:

total job count added
c086b57

Added functionality to display a running count of total matching jobs found during the search process, providing users with immediate feedback on their filter effectiveness.

minor current page issue fixed
5fcc005 -

Fixed a bug in the getCurrentPage function to ensure accurate tracking of the current page during navigation.

Exporting Results

After finding matching jobs, users needed a way to save and review the results outside of Naukri's interface.

Challenge #7: Implementing a CSV Export

Creating a downloadable CSV file directly from JavaScript without server-side processing required working with browser APIs and properly formatting the collected job data.

Solution:

I implemented an export function that:

  • Formatted collected job data as CSV with proper escaping
  • Created a Blob with the CSV content
  • Generated a temporary download link using URL.createObjectURL
  • Triggered a download with a meaningful filename including the search criteria and date

// Export matching jobs to CSV (for single page results)
const exportMatchingJobs = () => {
    const jobs = window.naukriMatchingJobs || [];
    
    if (!jobs || jobs.length === 0) {
    alert("No matching jobs to export");
    return;
    }
    
    // Get all unique fields from all job objects
    const excludeFields = ['element', 'postedDate', 'combinedText'];
    const allFields = new Set();
    
    jobs.forEach(job => {
    Object.keys(job).forEach(key => {
        if (!excludeFields.includes(key)) {
        allFields.add(key);
        }
    });
    });
    
    // Create CSV header row
    const fields = Array.from(allFields);
    let csv = fields.join(',') + '\n';
    
    // Add job data rows
    jobs.forEach(job => {
    const row = fields.map(field => {
        if (field === 'skills') {
        // Join skills array with semicolons
        return `"${job.skills ? job.skills.join('; ') : ''}"`;
        } else {
        // Escape quotes and wrap in quotes
        const value = job[field] !== undefined ? job[field] : '';
        return `"${String(value).replace(/"/g, '""')}"`;
        }
    }).join(',');
    
    csv += row + '\n';
    });
    
    // Create download link
    const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
    const url = URL.createObjectURL(blob);
    const link = document.createElement('a');
    link.setAttribute('href', url);
    link.setAttribute('download', config.exportFilename);
    link.style.visibility = 'hidden';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    
    console.log(`Exported ${jobs.length} jobs to ${config.exportFilename}`);
};
                                    

Refining the User Interface

With the core functionality complete, I focused on improving the user experience and addressing edge cases.

Challenge #8: Handling Edge Cases and Error States

Various situations could cause the script to fail, including no search results, network issues, or changes to Naukri's website structure. Additionally, the control panel needed to be non-intrusive while remaining accessible.

Solution:

I implemented comprehensive error handling and UI improvements:

  • Added status messages for various scenarios (no results, search complete, etc.)
  • Implemented timeouts for page loading with appropriate fallbacks
  • Made the control panel collapsible and draggable
  • Added visual indicators for matched jobs directly on the search results page

Key Commit:

cleaned the UI + added readme
2b84329 -

This final commit improved the user interface with cleaner styling and added comprehensive documentation in the form of a README file explaining installation and usage instructions.

Final UI

Optimization and Clean-up

Before finalizing the script, I went through several rounds of testing and optimization.

Challenge #9: Performance Optimization

Running the script on large result sets could potentially slow down the browser. Additionally, some features proved unnecessary or problematic in real-world usage.

Solution:

I optimized the script by:

  • Using more efficient DOM querying techniques
  • Implementing debounced event handlers to prevent excessive function calls
  • Removing features that weren't providing value

Key Commit:

removed job post day filter
f8df9d4 -

After testing, I found that the job posting date filter wasn't reliable across different searches and was removed to simplify the interface and improve performance.

Final Results and Insights

The completed Naukri Filter script has dramatically improved my job search efficiency. What used to take hours of manual filtering now happens automatically in minutes. Here are some key metrics from my usage:

What I Learned:

This project reinforced several important development principles:

  • Start with the user in mind: Understanding my own pain points as a job seeker helped shape a tool that genuinely solves problems
  • Progressive enhancement: Building the core functionality first, then adding features incrementally
  • Error resilience: Web scraping requires robust error handling due to the unpredictable nature of web pages
  • Performance matters: Even a small script can cause performance issues if not carefully optimized

Future Enhancements

While the current version of the script meets my immediate needs, I have several ideas for future improvements:

Project Conclusion

The Naukri Filter script has evolved from a simple idea to a fully functional tool that has significantly improved my job search efficiency. By automating the tedious process of filtering through hundreds of job listings, I can now focus my time and energy on applying to positions that truly match my skills and requirements.

Beyond the practical benefits, this project has been an excellent opportunity to deepen my understanding of DOM manipulation, browser automation, and user interface design. The iterative development process, documented through version control, reflects my approach to problem-solving and continuous improvement.

If you're interested in trying the script yourself or contributing to its development, check out the GitHub repository link below!